## Unzip the upload data into google drive.
# !unzip "/content/drive/MyDrive/Dog-Vision/dog-breed-identification (1).zip" -d "/content/drive/MyDrive/Dog-Vision/"
End-To-End Multi-class dog breed classification¶
In this project we are building end to end multiclass image classifier using tensorflow and tensorflow hub.
Problems¶
Identifying the breed of a dog given an image of a dog.
When I am outside my house and I see some dog, I want to know what breed that dog is.
Data¶
The data we are using is from kaggle.
Evaluation¶
The evaluation is a file with prediction probabilities for each dog breed of each test image.
Features¶
Some information about the data.
We are dealing with images (unstructured data) so its probably we use deep learning/transfer leraning.
There are 120 breeds of dogs (this means there are 120 different classes).
There are 10K+ images for tranning set and 10K+ images for testing set.(These images do not have a label)
import tensorflow as tf
import tensorflow_hub as hub
print("TensorFlow:", tf.__version__)
print("TF Hub:", hub.__version__)
print("Keras (from TF):", tf.keras.__version__)
TensorFlow: 2.19.0 TF Hub: 0.16.1 Keras (from TF): 3.10.0
## Lets check which GPU we are using if its available.
print("GPU Available: " "Yes:))"if tf.config.list_physical_devices("GPU") else "not available")
not available
Getting our data (Turning into tensors)¶
Lets start with accesing our data and checking it
import pandas as pd
label_csv = pd.read_csv("/content/drive/MyDrive/Dog-Vision/labels.csv")
label_csv.describe()
| id | breed | |
|---|---|---|
| count | 10222 | 10222 |
| unique | 10222 | 120 |
| top | fff43b07992508bc822f33d8ffd902ae | scottish_deerhound |
| freq | 1 | 126 |
label_csv.head()
| id | breed | |
|---|---|---|
| 0 | 000bec180eb18c7604dcecc8fe0dba07 | boston_bull |
| 1 | 001513dfcb2ffafc82cccf4d8bbaba97 | dingo |
| 2 | 001cdf01b096e06d78e9e5112d419397 | pekinese |
| 3 | 00214f311d5d2247d5dfe4fe24b2303d | bluetick |
| 4 | 0021f9ceb3235effd7fcde7f7538ed62 | golden_retriever |
label_csv.breed.value_counts().plot.bar(figsize=(25,10));
label_csv.breed.value_counts().median()
82.0
from IPython.display import Image
Image("/content/drive/MyDrive/Dog-Vision/train/001cdf01b096e06d78e9e5112d419397.jpg")
Let's get images and their labels.¶
filename = ["/content/drive/MyDrive/Dog-Vision/train/"+ fname+".jpg" for fname in label_csv.id]
filename[:10]
['/content/drive/MyDrive/Dog-Vision/train/000bec180eb18c7604dcecc8fe0dba07.jpg', '/content/drive/MyDrive/Dog-Vision/train/001513dfcb2ffafc82cccf4d8bbaba97.jpg', '/content/drive/MyDrive/Dog-Vision/train/001cdf01b096e06d78e9e5112d419397.jpg', '/content/drive/MyDrive/Dog-Vision/train/00214f311d5d2247d5dfe4fe24b2303d.jpg', '/content/drive/MyDrive/Dog-Vision/train/0021f9ceb3235effd7fcde7f7538ed62.jpg', '/content/drive/MyDrive/Dog-Vision/train/002211c81b498ef88e1b40b9abf84e1d.jpg', '/content/drive/MyDrive/Dog-Vision/train/00290d3e1fdd27226ba27a8ce248ce85.jpg', '/content/drive/MyDrive/Dog-Vision/train/002a283a315af96eaea0e28e7163b21b.jpg', '/content/drive/MyDrive/Dog-Vision/train/003df8b8a8b05244b1d920bb6cf451f9.jpg', '/content/drive/MyDrive/Dog-Vision/train/0042188c895a2f14ef64a918ed9c7b64.jpg']
## Let's check number of file names matches with actuall image or not.
import os
if len(os.listdir("/content/drive/MyDrive/Dog-Vision/train")) == len(filename):
print("Filenames match")
else:
print("file names do not match")
Filenames match
Image(filename[9000])
label_csv.breed[9000], label_csv
('tibetan_mastiff',
id breed
0 000bec180eb18c7604dcecc8fe0dba07 boston_bull
1 001513dfcb2ffafc82cccf4d8bbaba97 dingo
2 001cdf01b096e06d78e9e5112d419397 pekinese
3 00214f311d5d2247d5dfe4fe24b2303d bluetick
4 0021f9ceb3235effd7fcde7f7538ed62 golden_retriever
... ... ...
10217 ffd25009d635cfd16e793503ac5edef0 borzoi
10218 ffd3f636f7f379c51ba3648a9ff8254f dandie_dinmont
10219 ffe2ca6c940cddfee68fa3cc6c63213f airedale
10220 ffe5f6d8e2bff356e9482a80a6e29aac miniature_pinscher
10221 fff43b07992508bc822f33d8ffd902ae chesapeake_bay_retriever
[10222 rows x 2 columns])
Turning data labels into numbers¶
Since we have got our trainning images file path in list, lets prepare label.
import numpy as np
labels = label_csv.breed.to_numpy()
labels, len(labels)
(array(['boston_bull', 'dingo', 'pekinese', ..., 'airedale',
'miniature_pinscher', 'chesapeake_bay_retriever'], dtype=object),
10222)
if len(labels) == len(filename):
print("Numbers have matched")
else:
print("Numbers do not match, please check the file directory.")
Numbers have matched
## Let's find the unique breeds
unique_breeds = np.unique(labels)
len(unique_breeds), unique_breeds[:5]
(120,
array(['affenpinscher', 'afghan_hound', 'african_hunting_dog', 'airedale',
'american_staffordshire_terrier'], dtype=object))
## lets turn single labels into boolean arrays
print(labels[0])
labels[0] == unique_breeds
boston_bull
array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, True, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False])
## Turning every label into boolean arrays
boolean_labels = [label == unique_breeds for label in labels]
boolean_labels[:2]
[array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, True, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False]),
array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, True, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False])]
# Example of turning booleans arrays into numbers
print(labels[0])
print(np.where(unique_breeds == labels[0]))
print(boolean_labels[0].argmax())
print(boolean_labels[0].astype(int))
boston_bull (array([19]),) 19 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
labels[2], boolean_labels[2].astype(int)
('pekinese',
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
Creating validation set¶
X = filename
Y = boolean_labels
len(filename)
10222
## Lets start with only 1000 images right now and later on we will increase it as we need. Its because ML or DL model could really take awhile to train 10,000 images.
NUM_IMGS = 5000 #@param{type:"slider", min:1000, max: 10000, step: 1000}
## Lets split our data into train and validation using sklearn's train test split
from sklearn.model_selection import train_test_split
X_train, X_val, Y_train, Y_val = train_test_split(X[:NUM_IMGS], Y[:NUM_IMGS], test_size=0.2, random_state=42)
len(X_train), len(X_val)
(4000, 1000)
X_train[:2], Y_train[:2]
(['/content/drive/MyDrive/Dog-Vision/train/693f4cd00978df07e1283d3da4d02e0c.jpg',
'/content/drive/MyDrive/Dog-Vision/train/7521421e092333c78d6b9dc2e189e659.jpg'],
[array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, True, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False]),
array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, True, False, False, False, False, False,
False, False, False])])
Preprocessing images (Turning images into tensors)¶
tensors are matrix, something like numeric representation
## lets see what importing image looks like
from matplotlib.pyplot import imread
image = imread(filename[7])
image.shape, image[:2]
((227, 231, 3),
array([[[ 76, 97, 58],
[ 80, 101, 62],
[ 84, 104, 67],
...,
[ 67, 82, 51],
[ 67, 82, 51],
[ 37, 52, 19]],
[[ 91, 112, 73],
[ 94, 115, 76],
[ 93, 113, 76],
...,
[ 89, 102, 74],
[ 83, 96, 66],
[ 71, 84, 54]]], dtype=uint8))
tf.constant(image)[:2]
<tf.Tensor: shape=(2, 231, 3), dtype=uint8, numpy=
array([[[ 76, 97, 58],
[ 80, 101, 62],
[ 84, 104, 67],
...,
[ 67, 82, 51],
[ 67, 82, 51],
[ 37, 52, 19]],
[[ 91, 112, 73],
[ 94, 115, 76],
[ 93, 113, 76],
...,
[ 89, 102, 74],
[ 83, 96, 66],
[ 71, 84, 54]]], dtype=uint8)>
IMG_SIZE = 224
def process_img(img_path):
"""
1. Take an image file path as input.
2. Use TensorFlow to read the file.
3. Decode the image into a Tensor (RGB).
4. Normalize pixel values to the range [0, 1].
5. Resize the image to (224, 224).
6. Return the modified image Tensor.
"""
# Read the image file
image = tf.io.read_file(img_path)
# Decode JPEG image to tensor with 3 color channels (RGB)
image = tf.io.decode_jpeg(image, channels=3)
# Normalize pixel values from [0, 255] to [0, 1]
image = tf.image.convert_image_dtype(image, tf.float32)
# Resize the image to (224, 224)
image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
return image
Turning our data into batches¶
we will be turning our data into batches, because if we use our whole 10K + data in one go, they might not fit into memory.
We are going to use 32(batch size) images at a time.
In order to use tensorflow we need our data in form of (Image, label)
## Lets create a simple function which will return tuple (image, label)
def get_image_label(image_path, label):
"""
takes an image file path name and the associated label
processes the image and return the tuple (image, label)
"""
image = process_img(image_path)
return (image, label)
(process_img(X[42]), tf.constant(Y[42]))
(<tf.Tensor: shape=(224, 224, 3), dtype=float32, numpy=
array([[[0.3264178 , 0.5222886 , 0.3232816 ],
[0.2537167 , 0.44366494, 0.24117759],
[0.25699762, 0.4467087 , 0.23893751],
...,
[0.29325107, 0.5189916 , 0.3215547 ],
[0.29721776, 0.52466875, 0.33030328],
[0.2948505 , 0.5223015 , 0.33406618]],
[[0.25903144, 0.4537807 , 0.27294815],
[0.24375686, 0.4407019 , 0.2554778 ],
[0.2838985 , 0.47213382, 0.28298813],
...,
[0.2785345 , 0.5027992 , 0.31004712],
[0.28428748, 0.5108719 , 0.32523635],
[0.28821915, 0.5148036 , 0.32916805]],
[[0.20941195, 0.40692952, 0.25792548],
[0.24045378, 0.43900946, 0.2868911 ],
[0.29001117, 0.47937486, 0.32247734],
...,
[0.26074055, 0.48414773, 0.30125174],
[0.27101526, 0.49454468, 0.32096273],
[0.27939945, 0.5029289 , 0.32934693]],
...,
[[0.00634795, 0.03442048, 0.0258106 ],
[0.01408936, 0.04459917, 0.0301715 ],
[0.01385712, 0.04856448, 0.02839671],
...,
[0.4220516 , 0.39761978, 0.21622123],
[0.47932503, 0.45370543, 0.2696505 ],
[0.48181024, 0.45828083, 0.27004552]],
[[0.00222061, 0.02262166, 0.03176915],
[0.01008397, 0.03669046, 0.02473482],
[0.00608852, 0.03890046, 0.01207283],
...,
[0.36070833, 0.33803678, 0.16216144],
[0.42499566, 0.3976801 , 0.21701711],
[0.4405433 , 0.4139589 , 0.23183356]],
[[0.05608118, 0.06760313, 0.10401551],
[0.05441153, 0.07435327, 0.05428322],
[0.04734357, 0.07581862, 0.02060969],
...,
[0.3397557 , 0.3126567 , 0.14725593],
[0.3877246 , 0.3602736 , 0.187147 ],
[0.43942 , 0.41196904, 0.23884243]]], dtype=float32)>,
<tf.Tensor: shape=(120,), dtype=bool, numpy=
array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
True, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False])>)
now we got the function which return the data into tuple of tensors in the form of (image, label), lets make a function to turn all our data (X & Y) into batches.
# batch size
BATCH_SIZE = 32
# # create a function to turn our data into batches.
# def create_data_batches(X, Y=None, batch_size=BATCH_SIZE, valid_data= False, test_data=False):
# """
# create's batches of data out of image(X) and label(y) pairs.
# Shuffles the data if its trainning data but dosent if its validation data.
# Also accepts test data as input(no labels).
# """
# if test_data:
# print("Creating test data batches...")
# data = tf.data.Dataset.from_tensor_slices((tf.constant(X))) # only file paths no labels.
# data_batch = data.map(process_img).batch(batch_size)
# return data_batch
# elif valid_data:
# print("Creating a validation batches...")
# data = tf.data.Dataset.from_tensor_slices((tf.constant(X), # filepath
# tf.constant(Y))) # labels
# data_batch = data.map(get_image_label).batch(batch_size)
# return data_batch
# else:
# print("Creating a trainning batches...")
# data = tf.data.Dataset.from_tensor_slices((tf.constant(X), # filepath
# tf.constant(Y))) # labels
# data = data.shuffle(buffer_size=len(X))
# data_batch = data.map(get_image_label).batch(batch_size)
# return data_batch
def create_data_batches(X, Y=None, batch_size=BATCH_SIZE, valid_data=False, test_data=False):
if test_data:
print("Creating test data batches...")
data = tf.data.Dataset.from_tensor_slices(tf.constant(X))
data_batch = data.map(process_img, num_parallel_calls=tf.data.AUTOTUNE).batch(batch_size).prefetch(tf.data.AUTOTUNE)
return data_batch
elif valid_data:
print("Creating validation batches...")
data = tf.data.Dataset.from_tensor_slices((tf.constant(X), tf.constant(Y)))
data_batch = data.map(get_image_label, num_parallel_calls=tf.data.AUTOTUNE).batch(batch_size).prefetch(tf.data.AUTOTUNE)
return data_batch
else:
print("Creating training batches...")
data = tf.data.Dataset.from_tensor_slices((tf.constant(X), tf.constant(Y)))
data = data.shuffle(buffer_size=len(X))
data_batch = data.map(get_image_label, num_parallel_calls=tf.data.AUTOTUNE).batch(batch_size).prefetch(tf.data.AUTOTUNE)
return data_batch
training_data = create_data_batches(X_train, Y_train)
val_data = create_data_batches(X_val, Y_val, valid_data=True)
Creating training batches... Creating validation batches...
training_data.element_spec
(TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None))
val_data.element_spec
(TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None))
Lets Visualize our data¶
# import matplotlib.pyplot as plt
# def show_25_imgs(images, label):
# """
# Display a plot of 25 images with their labels
# """
# # setup the figure
# plt.figure(figsize=(10,10))
# for i in range (25):
# # create subplots (5 rows, 5 coloums)
# ax = plt.subplot(5,5, i+1)
# #Display an image
# plt.imshow(image[i])
# # add the image label
# # plt.title(unique_breeds[labels[i].argmax()])
# # turn the grid lines off
# plt.axis("off")
import matplotlib.pyplot as plt
def show_25_imgs(images, labels):
"""
Display a plot of 25 images with their labels
"""
# Setup the figure
plt.figure(figsize=(10, 10))
for i in range(25):
# Create subplots (5 rows, 5 columns)
ax = plt.subplot(5, 5, i + 1)
# Display the image
plt.imshow(images[i])
# Add the image label
plt.title(labels[i])
# add the image label
plt.title(unique_breeds[labels[i].argmax()])
# Turn the grid lines off
plt.axis("off")
plt.show()
# Now let's visualize our data in the training batch
train_images, train_label = next(training_data.as_numpy_iterator())
show_25_imgs(train_images, train_label)
Building our model¶
Before we built our model there are few things we have to define:
- The input shape(our images shape, in the form of tensors) to our model
- The output shape(image labels, in the form of Tensors) of our models.
- The URL of the model we want to use. :- mobilenet_v2 ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4"
# import tensorflow as tf
# import tensorflow_hub as hub
# from tensorflow.keras.models import Sequential
# from tensorflow.keras.layers import MaxPooling2D, Dense, Flatten, Dropout, Conv2D
# print("TensorFlow:", tf.__version__)
# print("TF Hub:", hub.__version__)
# print("Keras (from TF):", tf.keras.__version__)
# def build_simple_cnn(input_shape, num_classes):
# model = Sequential([
# Conv2D(32, (3,3), activation='relu', input_shape=input_shape),
# MaxPooling2D(),
# Conv2D(64, (3,3), activation='relu'),
# MaxPooling2D(),
# Conv2D(128, (3,3), activation='relu'),
# MaxPooling2D(),
# Flatten(),
# Dense(256, activation='relu'),
# Dropout(0.5),
# Dense(num_classes, activation='softmax')
# ])
# model.compile(optimizer='adam',
# loss='categorical_crossentropy',
# metrics=['accuracy'])
# return model
# model = build_simple_cnn(input_shape=(224, 224, 3), num_classes=len(unique_breeds))
# model.summary()
import tensorflow as tf
import tensorflow_hub as hub
def build_sequential_transfer_model(input_shape=(224,224,3),
num_classes=120,
feature_extractor_url="https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4",
trainable=False):
"""
Build a Sequential transfer learning model using TensorFlow Hub.
Args:
input_shape (tuple): Shape of input images (H, W, C).
num_classes (int): Number of output classes.
feature_extractor_url (str): TF Hub feature extractor URL.
trainable (bool): Whether to fine-tune the feature extractor.
Returns:
tf.keras.Sequential: A compiled Keras model using integer labels (sparse_categorical_crossentropy).
"""
# Load the feature extractor
feature_extractor_layer = hub.KerasLayer(
feature_extractor_url,
input_shape=input_shape,
trainable=trainable
)
# Named function to apply the feature extractor
def apply_feature_extractor(x):
return feature_extractor_layer(x)
# Build the sequential model
model = tf.keras.Sequential([
tf.keras.layers.InputLayer(input_shape=input_shape),
tf.keras.layers.Lambda(apply_feature_extractor),
tf.keras.layers.Dense(num_classes, activation="softmax")
])
# Compile the model
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss="categorical_crossentropy",
metrics=["accuracy"]
)
return model
model = build_sequential_transfer_model()
model.summary()
/usr/local/lib/python3.12/dist-packages/keras/src/layers/core/input_layer.py:27: UserWarning: Argument `input_shape` is deprecated. Use `shape` instead. warnings.warn(
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ lambda (Lambda) │ (None, 1280) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 120) │ 153,720 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 153,720 (600.47 KB)
Trainable params: 153,720 (600.47 KB)
Non-trainable params: 0 (0.00 B)
Tensorflow callbacks¶
%load_ext tensorboard
import datetime
def create_tensorboard_callback():
logdir = os.path.join("drive/MyDrive/Dog-Vision/logs",
datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
return tf.keras.callbacks.TensorBoard(logdir)
early_stopping = tf.keras.callbacks.EarlyStopping(monitor="val_accuracy", patience=3)
Trainning our model¶
NUM_EPOCHS = 100 #@param {type:"slider", min:10, max:100, step: 10 }
def train_model():
model = build_sequential_transfer_model()
tensorboard = create_tensorboard_callback()
model.fit(x=training_data, epochs=NUM_EPOCHS, validation_data = val_data, validation_freq=1, callbacks=[tensorboard, early_stopping])
return model
model = train_model()
Epoch 1/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 381s 3s/step - accuracy: 0.3259 - loss: 3.2853 - val_accuracy: 0.7590 - val_loss: 0.9624 Epoch 2/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 216s 2s/step - accuracy: 0.8816 - loss: 0.5757 - val_accuracy: 0.7740 - val_loss: 0.7762 Epoch 3/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 299s 2s/step - accuracy: 0.9404 - loss: 0.3195 - val_accuracy: 0.7970 - val_loss: 0.6608 Epoch 4/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 231s 2s/step - accuracy: 0.9765 - loss: 0.2114 - val_accuracy: 0.8130 - val_loss: 0.6308 Epoch 5/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 214s 2s/step - accuracy: 0.9828 - loss: 0.1441 - val_accuracy: 0.7980 - val_loss: 0.6125 Epoch 6/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 211s 2s/step - accuracy: 0.9929 - loss: 0.1047 - val_accuracy: 0.8070 - val_loss: 0.6083 Epoch 7/100 125/125 ━━━━━━━━━━━━━━━━━━━━ 304s 2s/step - accuracy: 0.9976 - loss: 0.0781 - val_accuracy: 0.8090 - val_loss: 0.5959
%tensorboard --logdir drive/MyDrive/Dog-Vision/logs
Making and evaluating the prediction using trained model¶
## We will make the prediction on the validation data
prediction = model.predict(val_data, verbose=1)
32/32 ━━━━━━━━━━━━━━━━━━━━ 45s 1s/step
prediction.shape
(1000, 120)
np.max(prediction[0]), np.argmax(prediction[0])
(np.float32(0.991989), np.int64(17))
unique_breeds[np.argmax(prediction[0])]
'border_terrier'
## let's understand the predictions
index = 56
print(prediction[index])
print(f"Max value (probabilty of prediction): {round(np.max(prediction[index]),2)}")
print(f"Index for the Max value: {np.argmax(prediction[index])}")
print(f"Predicted label: {unique_breeds[np.argmax(prediction[index])]}")
[3.24197958e-06 9.74646926e-01 1.21203198e-06 4.01908380e-07 4.07909595e-10 3.16296989e-10 1.48286858e-08 1.60433828e-07 3.20617168e-08 3.00882297e-09 6.47623679e-08 1.67129986e-06 5.93342309e-09 2.12556994e-08 2.01127259e-05 6.21981712e-07 4.38845618e-08 3.03715031e-09 2.76398623e-05 4.15059773e-08 1.22041116e-03 3.18247572e-07 2.38991248e-07 2.08251365e-02 1.10390346e-08 1.92158879e-07 3.20834943e-06 3.08224521e-08 1.53622977e-06 2.05818895e-09 1.11009889e-07 4.44990832e-07 2.98845634e-07 2.05927768e-06 4.72777053e-08 1.83498527e-09 2.29904367e-06 2.11277623e-07 3.79621383e-07 1.27322874e-09 1.06169518e-05 1.01947080e-06 4.63325094e-08 2.36961162e-09 1.14126815e-05 2.47554616e-10 2.27581131e-06 1.58696949e-07 4.61014897e-05 4.18409911e-07 6.87203374e-06 2.39673464e-05 2.92944691e-07 2.52318042e-08 8.15569656e-05 7.01083014e-09 3.04279683e-06 1.35391616e-07 7.96602478e-07 2.91831442e-04 5.01960926e-08 9.61283764e-09 2.13813152e-07 4.47630599e-09 6.22954133e-07 1.96839496e-03 5.04416953e-08 1.97824249e-07 9.59802051e-08 1.52999404e-04 8.13440465e-07 9.11485856e-08 3.50736491e-06 1.06303446e-07 7.95318442e-08 4.67737848e-09 1.45023469e-08 2.40946392e-08 1.37668801e-04 6.94192082e-08 2.70977232e-08 1.21769446e-07 5.40321651e-07 1.71083082e-06 3.15029780e-07 6.04500542e-07 2.26259611e-09 3.96316182e-06 8.11789391e-08 4.26361488e-08 8.33469528e-07 6.11658768e-09 5.22265282e-07 8.64686590e-05 4.67224737e-07 5.15626937e-08 2.00899121e-05 2.74120219e-04 7.92724180e-08 2.06627897e-06 5.69062095e-08 1.93547542e-08 1.01783871e-06 1.15843268e-05 2.06986623e-08 1.94120148e-05 1.71745882e-07 1.44386258e-05 1.93004189e-06 4.85731216e-05 5.89286060e-07 1.86688026e-10 5.58682736e-08 1.09777609e-09 5.21571451e-07 2.30206663e-08 1.30284645e-08 4.08598817e-06 8.35148728e-10 4.82032590e-07] Max value (probabilty of prediction): 0.9700000286102295 Index for the Max value: 1 Predicted label: afghan_hound
def get_prediction_label(index):
"""
This function will return the label with probability about how much sure it is about that particular prediction.
"""
return unique_breeds[np.argmax(prediction[index])], round(max(prediction[index]),2)
print(get_prediction_label(4))
('miniature_schnauzer', np.float32(0.87))
So from the result we can say that in the predictions for the 4 index, it has predicted that it is miniature_schnauzer and its 95% sure about that.
val_data
<_PrefetchDataset element_spec=(TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None))>
Now since our validation data is still batch dataset we have to still unbatch it to make prediction on the validation images and then compare it to the true lables¶
def unbatch(data):
images= []
labels= []
# loop through the unbatch data
for image, label in val_data.unbatch().as_numpy_iterator():
images.append(image)
labels.append(unique_breeds[np.argmax(label)])
return images, labels
val_images, val_label = unbatch(val_data)
label_ = [label for _, label in val_data.unbatch().as_numpy_iterator()]
val_images[0], val_label[0]
(array([[[0.08661207, 0.09751292, 0.07815619],
[0.06751302, 0.0918505 , 0.05747823],
[0.0604112 , 0.09729353, 0.04384629],
...,
[0.83837754, 0.8455904 , 0.79945946],
[0.7929071 , 0.7970798 , 0.7295842 ],
[0.8214812 , 0.826038 , 0.75354415]],
[[0.07184874, 0.09509204, 0.08496422],
[0.06569613, 0.096114 , 0.0656529 ],
[0.04666601, 0.09603959, 0.03923428],
...,
[0.74699265, 0.75564605, 0.6929895 ],
[0.72310936, 0.73635286, 0.6507261 ],
[0.75028026, 0.76419234, 0.67546123]],
[[0.04185049, 0.07891282, 0.07907913],
[0.03230042, 0.08288307, 0.05734802],
[0.02757026, 0.09470031, 0.03129049],
...,
[0.65601474, 0.67997307, 0.56799006],
[0.6598779 , 0.6838362 , 0.57188773],
[0.68698364, 0.710942 , 0.5989934 ]],
...,
[[0.326806 , 0.42850253, 0.3172997 ],
[0.6370607 , 0.7247883 , 0.66578096],
[0.8212689 , 0.88485324, 0.88262165],
...,
[0.4940238 , 0.4430434 , 0.41167086],
[0.5178251 , 0.45794126, 0.43134815],
[0.57821727, 0.51240844, 0.4858153 ]],
[[0.34572285, 0.44419917, 0.37828863],
[0.6643563 , 0.74021477, 0.7191527 ],
[0.86548394, 0.91482466, 0.9510319 ],
...,
[0.6353568 , 0.58967334, 0.5640606 ],
[0.66618913, 0.60861784, 0.57481176],
[0.52439374, 0.45772707, 0.4247848 ]],
[[0.30435544, 0.4080571 , 0.36557254],
[0.628554 , 0.70544475, 0.69471836],
[0.8558529 , 0.89135873, 0.92351204],
...,
[0.7205118 , 0.67656213, 0.6649621 ],
[0.7108757 , 0.64807475, 0.61342007],
[0.70078444, 0.6318506 , 0.5881006 ]]], dtype=float32),
'border_terrier')
def print_prediction(index):
'''
Function to print prediction vs true label
'''
pred_label = unique_breeds[np.argmax(prediction[index])]
pred_prob = round(np.max(prediction[index]), 2)
true_label = unique_breeds[label_[index]]
print(f"""Image {index}:
Predicted -> {pred_label} ({pred_prob*100}%),
True -> {true_label[0]}""")
# Lets Check first 10 images
for i in range(10):
print_prediction(i)
Image 0:
Predicted -> border_terrier (99.0%),
True -> border_terrier
Image 1:
Predicted -> pomeranian (63.0%),
True -> samoyed
Image 2:
Predicted -> yorkshire_terrier (39.0%),
True -> australian_terrier
Image 3:
Predicted -> irish_wolfhound (83.0%),
True -> irish_wolfhound
Image 4:
Predicted -> miniature_schnauzer (87.0%),
True -> miniature_schnauzer
Image 5:
Predicted -> giant_schnauzer (65.0%),
True -> giant_schnauzer
Image 6:
Predicted -> malinois (56.0%),
True -> malinois
Image 7:
Predicted -> japanese_spaniel (97.0%),
True -> japanese_spaniel
Image 8:
Predicted -> german_shepherd (90.0%),
True -> german_shepherd
Image 9:
Predicted -> collie (85.0%),
True -> collie
So overall from the resul we can say that, the model is performing really well. from above 10 results only one got failed.
Let's visualise those predictions.¶
def plot_preds(prediction_probabilities, labels, images, n=0):
"""
View the prediction, ground truth and image for sample n
"""
pred_prob = prediction_probabilities[n]
image = images[n]
true_label = labels[n]
# Get predicted label and probability
pred_label = np.argmax(pred_prob)
pred_label_name = unique_breeds[pred_label]
pred_confidence = round(np.max(pred_prob)*100, 2)
# Plot the image
plt.imshow(image)
plt.xticks([])
plt.yticks([])
if pred_label_name==true_label:
color = 'green'
else:
color = 'red'
# Title: Predicted, Confidence %, True label
plt.title(f"Predicted: {pred_label_name} ({pred_confidence}%), True: {true_label}", color=color)
plt.show()
plot_preds(prediction_probabilities=prediction,
labels=val_label,
images=val_images, n=1)
plot_preds(prediction_probabilities=prediction,
labels=val_label,
images=val_images, n=79)
Lets make a function to visualise the top 10 prediction for 1 particular dog breed or 1 dog image.¶
import matplotlib.pyplot as plt
import numpy as np
def plot_pred_conf(pred_probs, labels, n=0):
"""
Plot top 10 predicted classes and probabilities for a single image n.
Highlights true label in green if present in top 10.
"""
pred_prob = pred_probs[n]
true_label = labels[n]
# top 10 predictions
top10_idx = pred_prob.argsort()[-10:][::-1]
top10_values = pred_prob[top10_idx]
top10_labels = unique_breeds[top10_idx]
# setup bar plot
bars = plt.bar(np.arange(len(top10_labels)), top10_values, color="grey")
plt.xticks(np.arange(len(top10_labels)), labels=top10_labels, rotation='vertical')
plt.ylabel("Probability")
plt.title(f"Top 10 Predictions (Image {n})")
# highlight true label if present
if true_label in top10_labels:
bars[np.argmax(top10_labels == true_label)].set_color("green")
plt.show()
plot_pred_conf(pred_probs=prediction, labels = val_label, n=79)
def save_model(model, suffix=None):
"""
Save a TensorFlow model in native Keras format.
"""
model_dir = "drive/MyDrive/Dog-Vision/models"
os.makedirs(model_dir, exist_ok=True)
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
if suffix:
model_path = os.path.join(model_dir, f"{timestamp}-{suffix}.keras")
else:
model_path = os.path.join(model_dir, f"{timestamp}.keras")
print(f"Saving model to: {model_path}...")
model.save(model_path) # native Keras format
print("Done!")
import keras
def load_model(model_path):
keras.config.enable_unsafe_deserialization()
"""
Load a saved Keras model (with TensorFlow Hub layers) from disk.
"""
print(f"Loading model from: {model_path}")
model = tf.keras.models.load_model(
model_path,
custom_objects={"KerasLayer": hub.KerasLayer}
)
return model
save_model(model, suffix="5000-images-mobileNetV2-Adam")
Saving model to: drive/MyDrive/Dog-Vision/models/20250822-160839-5000-images-mobileNetV2-Adam.keras... Done!
load_5000_image_model2 = load_model('/content/drive/MyDrive/Dog-Vision/models/20250822-125926-5000-images-mobileNetV2-Adam.keras')
Loading model from: /content/drive/MyDrive/Dog-Vision/models/20250822-125926-5000-images-mobileNetV2-Adam.keras
model.evaluate(val_data)
32/32 ━━━━━━━━━━━━━━━━━━━━ 43s 1s/step - accuracy: 0.8121 - loss: 0.5767
[0.5958881378173828, 0.8090000152587891]
# load_5000_image_model2.evaluate(val_data)
# CREATE A MODEL FOR FULL DATA
full_data = create_data_batches(X, Y)
Creating training batches...
full_data
<_PrefetchDataset element_spec=(TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None))>
full_model = build_sequential_transfer_model()
/usr/local/lib/python3.12/dist-packages/keras/src/layers/core/input_layer.py:27: UserWarning: Argument `input_shape` is deprecated. Use `shape` instead. warnings.warn(
# create full model callbacks
full_model_callbacks = create_tensorboard_callback()
full_model_early_stopping = tf.keras.callbacks.EarlyStopping(monitor="accuracy", patience=3)
full_model.fit(x=full_data, epochs=NUM_EPOCHS,callbacks=[full_model_callbacks, full_model_early_stopping])
Epoch 1/100 320/320 ━━━━━━━━━━━━━━━━━━━━ 464s 1s/step - accuracy: 0.9992 - loss: 0.0104 Epoch 2/100 320/320 ━━━━━━━━━━━━━━━━━━━━ 435s 1s/step - accuracy: 0.9992 - loss: 0.0092 Epoch 3/100 320/320 ━━━━━━━━━━━━━━━━━━━━ 436s 1s/step - accuracy: 0.9994 - loss: 0.0081 Epoch 4/100 320/320 ━━━━━━━━━━━━━━━━━━━━ 429s 1s/step - accuracy: 0.9986 - loss: 0.0095
<keras.src.callbacks.history.History at 0x794d06d4a720>
save_model(full_model, suffix="full-image-set-mobilenetv2-Adam")
Saving model to: drive/MyDrive/Dog-Vision/models/20250822-185155-full-image-set-mobilenetv2-Adam.keras... Done!
Making Prediction on the test dataset.¶
To make predictions on the test dataset we will
- Get the test image filename
- Convert the filename into test data batches
- Make the prediction array by passing the test batches to the predict() method call on our model.
test_path = '/content/drive/MyDrive/Dog-Vision/test'
test_filenames = [os.path.join(test_path, fname) for fname in os.listdir(test_path)]
test_filenames[:5]
['/content/drive/MyDrive/Dog-Vision/test/e380bd4f8375d09ae72f4f36aa610031.jpg', '/content/drive/MyDrive/Dog-Vision/test/e6f07d64c2380bbde03a7b6ade01b859.jpg', '/content/drive/MyDrive/Dog-Vision/test/e7340d1efa70bf6d6c134e1e150f9473.jpg', '/content/drive/MyDrive/Dog-Vision/test/def639bab46dfc714234180be730ef49.jpg', '/content/drive/MyDrive/Dog-Vision/test/e406358fe35be30ac65f11936c2a066e.jpg']
len(test_filenames)
10357
test_data = create_data_batches(test_filenames, test_data=True)
Creating test data batches...
test_data
<_PrefetchDataset element_spec=TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None)>
test_predictions = full_model.predict(test_data,
verbose=1)
324/324 ━━━━━━━━━━━━━━━━━━━━ 718s 2s/step
# Check out the test predictions
test_predictions[:10]
array([[3.03081720e-08, 4.26958913e-09, 4.79092606e-08, ...,
9.98328687e-07, 2.12242405e-04, 1.03081248e-07],
[2.92825712e-06, 9.09930497e-14, 4.59487959e-09, ...,
3.69995541e-06, 1.18794297e-11, 2.66565503e-09],
[1.45384377e-07, 5.60959688e-06, 1.12201874e-08, ...,
1.15015686e-08, 3.98045381e-11, 6.37402409e-10],
...,
[3.04594350e-10, 7.17379822e-10, 5.79895207e-08, ...,
5.56451196e-09, 6.44481968e-10, 5.51422339e-08],
[7.15874471e-10, 9.54142632e-09, 1.96127070e-09, ...,
1.66329961e-09, 1.65533054e-09, 2.41703422e-08],
[5.61730512e-13, 4.08391756e-08, 6.98998082e-10, ...,
1.93506585e-05, 9.66688752e-13, 7.77828291e-09]], dtype=float32)
# Create pandas DataFrame with empty columns
preds_df = pd.DataFrame(columns=["id"] + list(unique_breeds))
preds_df.head()
| id | affenpinscher | afghan_hound | african_hunting_dog | airedale | american_staffordshire_terrier | appenzeller | australian_terrier | basenji | basset | ... | toy_poodle | toy_terrier | vizsla | walker_hound | weimaraner | welsh_springer_spaniel | west_highland_white_terrier | whippet | wire-haired_fox_terrier | yorkshire_terrier |
|---|
0 rows × 121 columns
# Append test image ID's to predictions DataFrame
test_path = "drive/MyDrive/Dog-Vision/test/"
preds_df["id"] = [os.path.splitext(path)[0] for path in os.listdir(test_path)]
preds_df.head()
| id | affenpinscher | afghan_hound | african_hunting_dog | airedale | american_staffordshire_terrier | appenzeller | australian_terrier | basenji | basset | ... | toy_poodle | toy_terrier | vizsla | walker_hound | weimaraner | welsh_springer_spaniel | west_highland_white_terrier | whippet | wire-haired_fox_terrier | yorkshire_terrier | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | e380bd4f8375d09ae72f4f36aa610031 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 1 | e6f07d64c2380bbde03a7b6ade01b859 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 2 | e7340d1efa70bf6d6c134e1e150f9473 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3 | def639bab46dfc714234180be730ef49 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 4 | e406358fe35be30ac65f11936c2a066e | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 121 columns
# Add the prediction probabilities to each dog breed column
preds_df[list(unique_breeds)] = test_predictions
preds_df.head()
| id | affenpinscher | afghan_hound | african_hunting_dog | airedale | american_staffordshire_terrier | appenzeller | australian_terrier | basenji | basset | ... | toy_poodle | toy_terrier | vizsla | walker_hound | weimaraner | welsh_springer_spaniel | west_highland_white_terrier | whippet | wire-haired_fox_terrier | yorkshire_terrier | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | e380bd4f8375d09ae72f4f36aa610031 | 3.030817e-08 | 4.269589e-09 | 4.790926e-08 | 5.713818e-10 | 4.483471e-08 | 5.763302e-10 | 1.181326e-06 | 6.958615e-08 | 8.526889e-10 | ... | 1.987472e-09 | 1.218193e-04 | 3.205971e-12 | 3.578717e-12 | 1.498647e-08 | 8.089582e-08 | 6.844852e-04 | 9.983287e-07 | 2.122424e-04 | 1.030812e-07 |
| 1 | e6f07d64c2380bbde03a7b6ade01b859 | 2.928257e-06 | 9.099305e-14 | 4.594880e-09 | 6.798813e-13 | 1.593340e-04 | 1.620335e-11 | 7.586689e-14 | 1.440272e-09 | 1.050382e-11 | ... | 4.473207e-10 | 9.417495e-09 | 1.618851e-08 | 1.393772e-10 | 5.663021e-09 | 1.038966e-12 | 1.562002e-10 | 3.699955e-06 | 1.187943e-11 | 2.665655e-09 |
| 2 | e7340d1efa70bf6d6c134e1e150f9473 | 1.453844e-07 | 5.609597e-06 | 1.122019e-08 | 1.351215e-08 | 3.184181e-09 | 2.820015e-06 | 9.225321e-09 | 3.347460e-09 | 1.127072e-09 | ... | 4.618546e-10 | 3.958469e-10 | 3.163429e-09 | 3.641087e-08 | 1.245477e-09 | 6.931596e-09 | 1.564855e-10 | 1.150157e-08 | 3.980454e-11 | 6.374024e-10 |
| 3 | def639bab46dfc714234180be730ef49 | 2.748204e-08 | 1.639920e-11 | 3.583094e-09 | 8.602932e-15 | 2.563571e-13 | 3.194448e-12 | 6.279288e-12 | 1.093741e-09 | 3.472514e-14 | ... | 2.578539e-08 | 3.846624e-12 | 6.627559e-12 | 1.230697e-14 | 6.252145e-09 | 5.356659e-15 | 1.374358e-08 | 2.161488e-08 | 1.254583e-13 | 2.288781e-08 |
| 4 | e406358fe35be30ac65f11936c2a066e | 2.570194e-09 | 1.754846e-11 | 4.888328e-11 | 2.516990e-05 | 1.247885e-07 | 1.825917e-05 | 5.145172e-07 | 3.081725e-05 | 2.134645e-10 | ... | 1.788220e-09 | 1.143040e-03 | 1.287161e-07 | 4.947580e-06 | 3.126805e-06 | 2.432209e-09 | 1.240297e-09 | 2.490954e-07 | 5.218654e-08 | 3.421207e-06 |
5 rows × 121 columns
preds_df.to_csv("drive/My Drive/Dog-Vision/full_submission_1_mobilienetV2_adam.csv",
index=False)
Let's try to make this prediction on our own pics and see what we get.¶
# Get custom image filepaths (safe join + filter)
custom_path = "drive/MyDrive/Dog-Vision/CustomPics/"
custom_image_paths = [
os.path.join(custom_path, fname)
for fname in os.listdir(custom_path)
if fname.lower().endswith((".jpg", ".jpeg", ".png"))
]
print("Custom images:", custom_image_paths)
Custom images: ['drive/MyDrive/Dog-Vision/CustomPics/Alaskan-Malamute.jpg', 'drive/MyDrive/Dog-Vision/CustomPics/german-shepherd.jpg', 'drive/MyDrive/Dog-Vision/CustomPics/Golden.jpg', 'drive/MyDrive/Dog-Vision/CustomPics/german-shepherd-2.jpg']
# Turn custom image into batch (no labels → test_data=True)
custom_data = create_data_batches(custom_image_paths, test_data=True)
Creating test data batches...
# Make predictions
custom_preds = full_model.predict(custom_data, verbose=1)
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 253ms/step
custom_preds
array([[3.31885652e-09, 4.99185582e-10, 2.26781918e-08, 2.28980127e-10,
8.17582890e-09, 2.39596875e-06, 6.52125798e-10, 1.54954341e-06,
4.05667618e-11, 1.65266574e-08, 1.19291554e-09, 2.71962023e-07,
3.51397977e-09, 4.33311733e-08, 1.07591165e-10, 1.78099438e-10,
5.69321967e-09, 2.93986030e-10, 2.37676886e-07, 1.17005712e-08,
1.22675159e-09, 6.76917244e-10, 4.47524212e-10, 8.92066776e-09,
1.79979226e-11, 4.02064299e-10, 3.12266185e-10, 1.21848132e-07,
1.36344136e-09, 1.22685805e-07, 8.75186998e-08, 2.82266810e-09,
1.32423725e-10, 4.28295550e-07, 1.36526621e-08, 4.13450003e-08,
6.35389630e-10, 2.61641864e-09, 1.59418718e-07, 3.10471004e-09,
2.82931945e-09, 1.19796422e-08, 1.21561941e-10, 3.68560641e-03,
2.96720213e-08, 7.23257685e-08, 8.76041995e-08, 6.12815299e-10,
2.49282834e-07, 4.41988703e-08, 2.69850337e-10, 1.31438691e-08,
8.72189389e-07, 1.89344457e-10, 2.72974376e-07, 3.30160099e-09,
1.20875576e-09, 6.89166146e-09, 3.92856137e-10, 6.00763306e-09,
7.51721185e-10, 7.80928713e-06, 9.76865977e-06, 1.54811941e-10,
2.41204212e-08, 3.53985863e-09, 6.07998629e-07, 2.40206095e-08,
1.46721313e-09, 1.50043377e-07, 8.58266569e-10, 9.93950963e-01,
3.81817911e-10, 1.70815329e-09, 1.89501370e-09, 3.13774451e-09,
6.36876285e-09, 1.12298810e-08, 2.20839297e-07, 9.33353306e-08,
1.36522681e-03, 1.35585992e-07, 2.55434003e-07, 4.72476325e-09,
9.74976160e-07, 3.24680216e-09, 2.21212604e-09, 8.46017585e-08,
3.72355288e-07, 3.02483620e-08, 1.26461543e-07, 9.78140624e-11,
1.83191453e-08, 4.25097113e-07, 9.36676770e-06, 5.35683625e-07,
1.35988651e-08, 5.48597745e-09, 1.88790388e-08, 3.57055825e-08,
1.07656597e-07, 9.05148452e-04, 9.33105415e-09, 8.60254090e-11,
6.63512134e-09, 2.38314442e-05, 4.24956261e-06, 7.75506859e-09,
2.59601802e-05, 6.67262725e-08, 4.28139124e-09, 2.86510300e-08,
1.58528013e-09, 9.53204449e-08, 1.63234404e-07, 3.16903814e-09,
6.27814103e-08, 1.70817369e-08, 8.26676150e-09, 1.73689385e-09],
[1.50521557e-11, 6.47091181e-09, 1.06844720e-06, 2.83677859e-09,
5.98862016e-10, 9.68025304e-09, 7.68487718e-10, 6.30428048e-08,
3.02237846e-10, 1.12945563e-10, 3.30467494e-11, 1.33679341e-12,
1.17955823e-09, 2.17697371e-11, 1.45832956e-07, 5.11870199e-11,
8.76264686e-12, 2.01922408e-08, 6.38686493e-10, 4.77901096e-09,
1.24168578e-10, 2.41092946e-09, 2.39123921e-07, 1.81902262e-08,
3.01579650e-10, 1.09850184e-07, 1.29874593e-07, 7.73745086e-08,
1.85330018e-09, 1.39755558e-08, 1.44976586e-10, 1.37467451e-11,
1.84235049e-12, 3.83585608e-09, 8.85676532e-11, 1.10522902e-11,
8.83300072e-06, 2.79432788e-05, 6.21821314e-08, 5.93826599e-10,
1.54075600e-10, 2.10845339e-12, 2.21910944e-12, 5.22378585e-10,
3.38956141e-10, 2.36488535e-08, 5.32766979e-04, 4.18075435e-10,
2.97938840e-10, 1.71204761e-07, 1.43849255e-09, 3.77319680e-07,
5.22118286e-11, 5.69109031e-11, 1.46837102e-08, 3.95172997e-08,
2.07230375e-08, 1.15040946e-08, 4.51055138e-10, 2.18524221e-09,
1.38159235e-08, 1.42968077e-11, 2.63117222e-10, 2.74000763e-06,
4.46224696e-10, 7.93287172e-11, 2.63004587e-08, 7.34684278e-08,
6.95280292e-11, 1.99700558e-08, 6.42515346e-11, 1.94730632e-08,
9.99420881e-01, 2.67662276e-13, 7.72362014e-08, 1.74901757e-07,
1.37265854e-09, 1.13590293e-09, 1.60232841e-10, 5.46360212e-13,
6.00800689e-08, 4.49670440e-10, 5.72997162e-12, 2.10848665e-11,
1.21427002e-09, 1.23011157e-10, 4.66842787e-10, 4.27394890e-11,
3.67673836e-10, 3.68100331e-07, 2.51050506e-06, 1.13205723e-09,
2.74933076e-10, 1.81340383e-08, 1.96706956e-11, 2.32085878e-10,
2.13327489e-08, 1.27768605e-08, 2.86411866e-10, 4.90231578e-10,
1.82743293e-10, 3.35666117e-09, 6.24608409e-09, 1.99010697e-09,
1.51466146e-08, 9.26227806e-09, 1.16486390e-10, 7.34324546e-11,
1.42223126e-11, 1.47246330e-11, 2.30344684e-11, 7.77741160e-09,
2.36446485e-09, 4.27700320e-09, 2.58094518e-10, 1.92354865e-11,
6.84419622e-12, 7.82878033e-07, 6.22877139e-10, 1.37852507e-09],
[3.18189268e-12, 3.87228388e-10, 2.93594281e-11, 7.86306159e-11,
5.25739416e-08, 1.71229768e-08, 5.55518964e-09, 1.28386982e-10,
3.11074522e-09, 1.96411758e-08, 1.18763743e-09, 7.63426087e-08,
3.05518666e-11, 2.54787497e-10, 9.09297984e-11, 1.39424444e-10,
2.92215940e-08, 4.90649086e-08, 1.69371130e-08, 1.56547388e-12,
7.30730919e-14, 2.88011086e-12, 4.27065284e-12, 5.03664710e-09,
4.30929333e-07, 2.32694378e-10, 6.76964942e-11, 4.31906670e-08,
2.48624559e-07, 2.30436670e-09, 8.01609203e-05, 2.25479685e-04,
2.35175918e-04, 5.83799356e-08, 6.54520491e-08, 3.15982305e-07,
1.42186924e-12, 1.80399809e-07, 8.37849416e-14, 1.53760737e-11,
6.15478211e-06, 1.09475977e-10, 2.24802665e-08, 4.00635872e-05,
2.76435429e-07, 3.48416504e-11, 1.93072114e-09, 1.01044346e-08,
2.42833198e-09, 9.35074627e-01, 5.20600185e-09, 6.11836484e-11,
2.35059001e-02, 1.89584834e-10, 6.00582986e-11, 1.96409469e-12,
5.24865654e-12, 8.01511675e-08, 2.85904529e-11, 2.28015953e-08,
1.22685759e-12, 6.20776069e-11, 4.56190153e-13, 7.01322245e-09,
1.17220081e-10, 5.62426798e-08, 2.77045127e-02, 1.28368214e-02,
1.20332331e-08, 3.00864428e-07, 2.56693049e-08, 1.30849669e-08,
1.12751909e-12, 3.52070657e-07, 1.40396904e-13, 3.96518235e-12,
3.24079920e-05, 1.26275249e-11, 1.88862687e-04, 6.49214815e-09,
3.32265171e-09, 2.84827550e-10, 2.49612413e-07, 1.36363232e-08,
1.67335017e-08, 1.39748861e-08, 2.70764282e-08, 6.65954616e-08,
2.40469061e-10, 9.67797842e-09, 2.39856757e-09, 1.35853631e-08,
1.04106235e-07, 6.80829828e-08, 5.72900644e-05, 9.47058543e-10,
2.59101129e-10, 8.43052642e-11, 2.23314103e-07, 5.38467493e-09,
1.03978834e-07, 1.03043254e-10, 2.51427545e-10, 1.91932531e-06,
1.72807564e-08, 6.07764332e-06, 1.81199912e-12, 7.25095006e-08,
6.42678287e-07, 9.11233045e-09, 5.65488136e-08, 9.18849307e-13,
5.68833480e-10, 9.19024301e-10, 2.03959907e-08, 2.48019694e-09,
7.97056199e-10, 1.07960041e-09, 2.09673147e-11, 2.45022752e-12],
[1.45812262e-09, 6.08993901e-07, 3.99423607e-06, 1.46895112e-03,
8.34224991e-08, 8.89767034e-05, 7.76387969e-06, 2.07823427e-06,
4.10909600e-08, 2.26323944e-04, 9.71371961e-08, 1.11575593e-08,
8.10841175e-06, 2.74429990e-08, 6.28598445e-06, 1.83342330e-04,
4.43915260e-09, 8.29335761e-07, 2.65229323e-06, 1.06798552e-07,
3.59188022e-08, 2.15470142e-10, 7.22459220e-07, 1.88593106e-07,
3.12533786e-08, 9.33190108e-07, 1.42677683e-08, 1.26480186e-08,
2.86125594e-08, 2.87413570e-07, 9.41977696e-09, 7.49746309e-09,
5.56296564e-09, 7.69671988e-06, 7.93317412e-08, 5.19599901e-08,
4.92917820e-07, 7.09222804e-04, 2.13568419e-04, 3.47626592e-05,
8.56257216e-08, 1.77324766e-10, 7.80278897e-10, 1.31370243e-05,
1.92557117e-08, 2.61249666e-09, 9.94852960e-01, 1.90934671e-07,
1.07929957e-07, 3.64831885e-06, 6.60393766e-07, 1.22200291e-07,
5.17548226e-09, 4.78183097e-07, 3.26918462e-06, 1.16727881e-06,
3.65272648e-08, 3.31980374e-07, 2.77559504e-08, 3.15742764e-05,
7.55677831e-07, 2.29852244e-08, 1.96061585e-08, 2.50311423e-04,
1.67262701e-08, 1.01890931e-08, 3.23684475e-07, 8.35763785e-07,
9.19495869e-06, 4.41558612e-08, 7.79491971e-10, 4.73448245e-06,
3.56370409e-04, 2.15090150e-08, 1.59563638e-06, 5.24157088e-07,
6.45320938e-07, 3.67237725e-08, 6.64407338e-08, 9.57943391e-10,
5.88366504e-07, 1.21703451e-07, 2.68731668e-08, 9.45852720e-04,
1.44179491e-09, 2.01793515e-08, 2.38856668e-09, 7.18917761e-08,
2.45117282e-09, 6.25343034e-07, 5.91580647e-06, 4.95887525e-06,
2.94222091e-09, 2.39463727e-04, 1.45173527e-08, 1.26965960e-09,
2.14196003e-08, 2.75112120e-06, 8.77336315e-10, 4.38179632e-06,
9.28962152e-08, 4.81325560e-06, 2.35698349e-06, 2.03040829e-09,
1.84979427e-07, 4.82263601e-07, 4.83056439e-08, 1.84927551e-09,
3.58204204e-08, 6.72936595e-09, 1.19138421e-09, 1.82893255e-05,
8.75762325e-08, 4.35977108e-06, 3.64573310e-07, 1.34761544e-08,
1.15524958e-08, 6.80357625e-05, 1.82689211e-04, 1.15168505e-05]],
dtype=float32)
def get_prediction_label(prediction_probs):
"""
Takes a prediction probability array and returns the predicted label
with its confidence.
"""
pred_index = np.argmax(prediction_probs) # index of max probability
pred_label = unique_breeds[pred_index] # map index to label
confidence = round(float(np.max(prediction_probs)), 2)
return pred_label, confidence
custom_pred_labels = [get_prediction_label(p) for p in custom_preds]
custom_pred_labels
[('malamute', 0.99),
('malinois', 1.0),
('golden_retriever', 0.94),
('german_shepherd', 0.99)]
custom_images = []
# Loop through unbatched data
for image in custom_data.unbatch().as_numpy_iterator():
custom_images.append(image)
import math
n_images = len(custom_images)
cols = 3
rows = math.ceil(n_images / cols)
plt.figure(figsize=(15, rows * 5))
for i, image in enumerate(custom_images):
plt.subplot(rows, cols, i + 1)
plt.imshow(image)
plt.xticks([])
plt.yticks([])
label, conf = custom_pred_labels[i]
plt.title(f"{label}\n({conf*100:.1f}%)")
plt.tight_layout()
plt.show()
There we go boom...¶